/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 huliqing, huliqing.cn@gmail.com
 *
 * This file is part of QFaces.
 * QFaces is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QFaces is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with QFaces.  If not, see <http://www.gnu.org/licenses/>.
 *
 * 这个文件是QFaces的一部分。
 * 您可以单独使用或分发这个文件，但请不要移除这个头部声明信息.
 * QFaces是一个自由软件，您可以自由分发、修改其中的源代码或者重新发布它，
 * 新的任何修改后的重新发布版必须同样在遵守LGPL3或更后续的版本协议下发布.
 * 关于LGPL协议的细则请参考COPYING、COPYING.LESSER文件，
 * 您可以在QFaces的相关目录中获得LGPL协议的副本，
 * 如果没有找到，请连接到 http://www.gnu.org/licenses/ 查看并获取副本。
 *
 * - Author: Huliqing
 * - Contact: huliqing.cn@gmail.com
 * - License: GNU Lesser General Public License (LGPL)
 * - Blog and source code availability: http://www.huliqing.name/
 */


// 代码分析
Q.F.UIEditor.Editor.CodePanel = function(editor) {
	this.editor = editor; // 相关的editor
	this.panel = null; // 主面板,由header,content组成
	this.select = null; // 代码列表项,id -> select
	this.input = null; // 代码区控件,id -> input
	this.submit = null; // 提交按钮,id -> submit
	this.exit = null; // 退出按钮
	this.language = Q.F.UIEditor.Language.languages; // 支持的语言
	this.codeIndex = 0; // 用于标记所插入的不同的代码段,会一直递增

	this.init = function(_self) {
		// 定义控件
		this.panel = document.createElement("div");
		this.select = createLanguageSelect(this.language);
		this.input = createTextarea();
		this.submit = Q.F.UIEditor.Utils.createButton("确定");
		this.exit = Q.F.UIEditor.Utils.createButton("退出");

		var header = Q.F.UIEditor.Utils.createHeader("Insert Code");
		var table = document.createElement("table");
		var rows = Q.F.UIEditor.Utils.createTable(table, 3, 2);
		rows[0].columns[0].innerHTML = "语言";
		rows[0].columns[1].appendChild(this.select);
		rows[1].columns[0].innerHTML = "代码";
		rows[1].columns[1].appendChild(this.input);
		rows[2].columns[0].innerHTML = "";
		rows[2].columns[1].appendChild(this.submit);
		
		this.submit.onclick = function() {_self.getCode();}
		this.exit.onclick = function() {_self.setVisible(false);}

		this.panel.style.cssText = "width:430px;border:3px solid #C0C0C0;background:#FFF;position:absolute;";
		header.style.cursor = "move";
		table.setAttribute("border", "0");
		table.setAttribute("cellspacing", "3");
		table.setAttribute("cellpadding", "3");
		rows[0].columns[0].width = 40;

		this.panel.appendChild(header);
		this.panel.appendChild(table);
		Q.U.toEnableDrag(header, this.panel);
		this.setVisible(false); // 默认为关闭的

		function createLanguageSelect(language) {
			var sel = document.createElement("select");
			for ( var i = 0; i < language.length; i++) {
				var opt = new Option();
				opt.value = language[i];
				opt.text = language[i];
				sel.options.add(opt);
			}
			return sel;
		}
		function createTextarea() {
			var area = document.createElement("textarea");
			area.style.cssText = "width:360px;height:200px;border:1px solid #C0C0C0;";
			return area;
		}
	}
	this.setVisible = function(bool) {
		if (!this.panel)
			this.init();
		this.panel.style.display = bool ? "block" : "none";
	}
	this.isVisible = function() {
		return (this.getPanel().style.display != "none");
	}
	this.getPanel = function() {return this.panel;}
	// 获取input中的代码并分析
	this.parseCode = function() {
		this.codeIndex++;
		var _text = Q.F.UIEditor.Parser.parse(this.input.value, this.select.value, this.editor.clientId, this.codeIndex);
		return _text;
	}
	this.getCode = function() {
		var htmlCode = this.parseCode();
		htmlCode = "<div style='border:1px solid #CCCCCC;background:#EEEEEE'>" + htmlCode + "</div>"
		this.editor.execHTMLCode(htmlCode);
		this.input.value = "";
		this.setVisible(false);
	}
	// 初始化
	this.init(this);
}
Q.F.UIEditor.Parser = {
	// text -> 代码, type -> 类型[language]
	parse : function(text, language, clientId, codeIndex) {
		if (text == null || text == "")
			return "";

		// 1.把数据拆分成行数组
		var _lines = this.parseToLines(text);

		// 2.分析每一行,将每一行数据拆分成带双引号与不带双引号的
		var _wordChain = this.parseToWords(_lines, clientId, codeIndex);

		// 3.获取关键词
		var _keyObj = Q.F.UIEditor.Language.getKeyObj(language);

		// 4.关键词高亮
		var _replaces = this.replaceByKeyObj(_keyObj, _wordChain);

		// 5.OK,return value;
		return _replaces;
	},
	parseToLines : function(text) {
		var _arr = new Array();
		_arr = text.split("\n");
		var numLen = _arr.length.toString().length;
		for ( var i = 0; i < _arr.length; i++) {
			var numCount = (i + 1).toString();
			while (numCount.length < numLen) {
				numCount = "0" + numCount;
			}
			_arr[i] = numCount + " " + _arr[i];
		}
		return _arr;
	},
	// 把所有Data串成一个单词链
	parseToWords : function(lines, clientId, codeIndex) {
		var firstWord = new Word();
		var lastWord = firstWord;
		var i = 0;
		do {
			lastWord = parseLine(lastWord, lines[i], clientId, i, codeIndex);
			i++;
		} while (i < lines.length);
		return firstWord;

		// 该方法将line拆分成一个word链,然后链接到lastWord的nextWord中,最后返回该链的最后一个word(新的lastWord)
		// clientId,lineNum主要用来标识节点内的{}中的代码块,格式: clientId:lineNum:(0 - ...)
		function parseLine(lastWord, line, clientId, lineNum, codeIndex) {
			var withBraces = false; // 当前行是否包含 花括号的起始符({),Note:双引号内的不算
			var code = ''; // 当前字符
			var codeLast = ''; // 最后一次遇到的字符
			var quote = 0; // 双引号数
			var currentInQuote = false; // 当前是否处于双引号内
			var newWord = false; // 单词是否结束，如果true,则需另起新word
			var bracesCount = 0; // 计算{个数(双引号内的不算)
			var nodeFlag  = clientId + ":" + codeIndex + ":" + lineNum + ":flag";
			var nodeCode  = clientId + ":" + codeIndex + ":" + lineNum + ":code";
			var nodeOpen  = clientId + ":" + codeIndex + ":" + lineNum + ":open";
			var nodeClose = clientId + ":" + codeIndex + ":" + lineNum + ":close";

			var startWord = new Word; // 链头
			startWord.data += "<br />";
			startWord.type = 0;
			var endWord = startWord.createNext();
			for ( var n = 0; n < line.length; n++) {
				code = line.charAt(n);
				// 如果遇到双引号，这时需要先知道该双引号是否是经过转义的。这从前一个code(codeLast)是否为"\"可判断出
				// 如果为转义的",则直接作为字符串处理。
				if (code == '"') {
					if (codeLast == '\\') {
						endWord.data += "" + code;
					} else {
						quote++;
						if (quote % 2 == 0) {
							// 偶引号,字符串结束。并标注已跳出双引号外
							newWord = true;
							currentInQuote = false;
							endWord.data += "" + code;
						} else {
							// 奇引号,开始新词(字符串)，并标注已进入双引号内,双引号内的全部认为是一个单词
							newWord = false;
							currentInQuote = true;
							endWord = endWord.createNext();
							endWord.type = 2;
							endWord.data += "" + code;
						}
					}
				} else if (
				// 处理单词分隔符及特殊字符,这些符号都可能是单词的分隔符
				code == '.' || code == '=' || code == ' ' || code == '\r'
						|| code == '\t' || code == '<' || code == '>'
						|| code == ',' || code == '(' || code == ')'
						|| code == '{' || code == '}' || code == ':') {
					// 如果在双引号内则继续，否则把该特殊字符处理为一个"单独的单词",然后标志新单词开始
					// Note：花括号较特殊,遇到"起始"花括号时需标记，递增bracesCount, 并产生{}代码块ID,
					if (currentInQuote) {
						endWord.data += convertHtmlCode(code);
					} else {
						newWord = true;
						endWord = endWord.createNext();
						endWord.type = 0;
						if (code == '{') {
							endWord.data += code;
							endWord.data += "<span id='" + nodeFlag + "' style='display:none;'> ... </span>";
							endWord.data += "<span id='" + nodeCode + "'>";
							withBraces = true;
							bracesCount++
						} else if (code == '}') {
							// 代码块结束符
							endWord.data += "</span>";
							endWord.data += code;
						} else {
							endWord.data += convertHtmlCode(code);
						}
					}
				} else {
					endWord.data += code;
				}
				codeLast = code;
				if (newWord) {
					newWord = false;
					endWord = endWord.createNext();
				}
			}
			// End of process, 如果有花括号,则插入标记: 
			// 替换操作会在解码阶段进行，注意nodeIds的id是不完整的（每个id必须区分flag,code）
			if (withBraces) {
				var openEvent = "this.style.display='none'; document.getElementById('" + nodeClose + "').style.display='';document.getElementById('" + nodeCode + "').style.display='';document.getElementById('" + nodeFlag + "').style.display='none';";
				var closeEvent = "this.style.display='none';document.getElementById('" + nodeOpen  + "').style.display='';document.getElementById('" + nodeFlag + "').style.display='';document.getElementById('" + nodeCode + "').style.display='none';";
				startWord.data += "<span><span id=\"" + nodeOpen + "\" onclick=\"" + openEvent + "\" style=\"display:none;cursor:pointer;\"><qfaces-node-editor>+</qfaces-node-editor></span><span id=\"" + nodeClose + "\" onclick=\"" + closeEvent + "\" style=\"cursor:pointer;\"><qfaces-node-editor>-</qfaces-node-editor></span></span>";
			} else {
				startWord.data += "<span style=\"margin:0 4px 0 7px;border-left:1px dotted gray;\">&nbsp;</span>";
			}
			// 拼接单词链
			lastWord.setNext(startWord);
			return endWord;
		}
		function convertHtmlCode(code) {
			if (code == '\t') {
				return "&nbsp;&nbsp;&nbsp;&nbsp;";
			} else if (code == ' ') {
				return "&nbsp;";
			} else if (code == '\r') {
				return "";
			} else if (code == '<') {
				return "&lt;";
			} else if (code == '>') {
				return "&gt;";
			} else {
				return code;
			}
		}
		function Word() {
			this.type = 1; // 0特殊字符(不高亮)，1单词(可能含关键字)，2字符串(蓝色高亮)
			this.data = ""; // Data
			this.previousWord; // 上一个单词
			this.nextWord; // 下一个单词

			this.setNext = function(nextWord) {
				this.nextWord = nextWord;
				this.nextWord.previousWord = this;
			}
			this.createNext = function() {
				this.setNext(new Word());
				return this.nextWord;
			}
		}
	},
	replaceByKeyObj : function(keyObj, wordChain) {
		if (wordChain == null) {
			alert("wordChain not found");
			return;
		}
		var _replaces = "";
		var currentWord = wordChain;
		do {
			_replaces += replaceOneWord(keyObj, currentWord);
		} while ((currentWord = currentWord.nextWord) != null);
		return _replaces;

		function replaceOneWord(keyObj, word) {
			if (keyObj == null || word == null)
				return "";
			var replace = word.data;
			if (word.type == 1) {
				for ( var i = 0; i < keyObj.keywords.length; i++) {
					if (replace == keyObj.keywords[i]) {
						replace = "<font color=" + keyObj.keywordColor + "><strong>" + replace + "</strong></font>";
						break;
					}
				}
			} else if (word.type == 2) {
				replace = "<font color=" + keyObj.stringColor + ">" + replace + "</font>";
			}
			return replace;
		}
	}
}
Q.F.UIEditor.Language = {
	languages : [ "Java", "JavaScript" ],
	getKeywords : function(language) {
		if (language == "Java") {
			return [ "abstract", "boolean", "break", "byte", "case", "catch",
					"char", "class", "continue", "default", "do", "double",
					"else", "extends", "false", "final", "finally", "float",
					"for", "if", "implements", "import", "instanceof", "int",
					"interface", "long", "native", "new", "null", "package",
					"private", "protected", "public", "return", "short",
					"static", "super", "switch", "synchronized", "this",
					"throw", "throws", "transient", "true", "try", "void",
					"volatile", "while", "const", "goto" ];
		} else if (language == "JavaScript") {
			return [ "abstract", "break", "case", "catch", "class", "const",
					"continue", "debugger", "default", "delete", "do",
					"double", "else", "export", "extends", "false", "final",
					"finally", "for", "function", "goto", "if", "implements",
					"in", "instanceof", "interface", "new", "null", "package",
					"private", "protected", "public", "return", "static",
					"super", "switch", "synchronized", "this", "throw",
					"throws", "transient", "true", "try", "typeof", "var",
					"volatile", "while" ];
		}
	},
	getKeyObj : function(language) {
		var keywords = this.getKeywords(language);
		if (keywords == null) {
			return null;
		} else {
			keyObj = new KeyObj(keywords);
			return keyObj;
		}
		function KeyObj(keywords) {
			this.keywords = keywords; // 关键词
			this.keywordColor = "#7F0091"; 	// 关键词颜色
			this.stringColor = "BLUE"; 		// 字符串颜色
			this.commentColor = "GRAY"; 	// 注释颜色
		}
	}
}